﻿using FFmpeg.NET;
using System.Diagnostics;
using System.Drawing.Drawing2D;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using VideoTools.Commands;
using VideoTools.vo;

namespace VideoTools.VideoView
{
    /// <summary>
    /// MargeM3U8Page.xaml 的交互逻辑
    /// </summary>
    public partial class RemoveWatermarkPage : System.Windows.Controls.Page
    {
        public DeviceType DeviceType = DeviceType.GPU;

        private static volatile RemoveWatermarkPage _instance;
        private static object _syncRoot = new object();
        private string videoPath;
        private bool processing = false;
        private double scale = 1;
        private int Duration;
        private string picPath;
        private DateTime StartTime;

        [DllImport("user32.dll", SetLastError = true)]

        private static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);

        [DllImport("user32.dll")]
        private static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
        public static RemoveWatermarkPage Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (_syncRoot)
                    {
                        if (_instance == null)
                        {
                            _instance = new RemoveWatermarkPage();
                        }

                    }
                }
                return _instance;
            }
        }

        public RemoveWatermarkPage()
        {
            InitializeComponent();
        }

       
        void OpenVideo_Click(object Sender, RoutedEventArgs Args)
        {
            
            OpenFileDialog openFileDialog = new OpenFileDialog();
            string filter = "视频文件(*.mp4)|*.mp4";
            openFileDialog.Filter = filter;
            openFileDialog.RestoreDirectory = true;
            openFileDialog.FilterIndex = 1;
            if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                this.videoPath = openFileDialog.FileName;
                this.ResetPicbox_Click(null, null);
            }
            else
            {
                return;
            }

        }
        public void GetVideoInfo()
        {
            Engine ffmpeg = new Engine(@"ffmpeg.exe");
            CancellationToken token = new CancellationToken();
            InputFile inputFile = new InputFile(this.videoPath);
            MetaData data = ffmpeg.GetMetaDataAsync(inputFile, token).GetAwaiter().GetResult();
            if (data == null)
            {
                return;
            }
            int seconds = (int)data.Duration.TotalSeconds;
            Duration = seconds;
            if (data.VideoData != null)
            {
                StringBuilder sb = new StringBuilder();
                Random random = new Random();
                TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
                for (int i = 0; i < 10; i++)
                {
                    int index = random.Next(AppConstants.Chars.Length);
                    sb.Append(AppConstants.Chars[index]);
                }
                picPath =
                    "./"
                    + AppConstants.ImageFileStart
                    + Convert.ToInt64(ts.TotalMilliseconds).ToString()
                    + "_"
                    + sb.ToString()
                    + ".jpg";
                var outputFile = new OutputFile(picPath);
                int durationMilliseconds = (int)data.Duration.TotalMilliseconds;
                ConversionOptions conversionOptions = new ConversionOptions()
                {
                    Seek = TimeSpan.FromMilliseconds(random.Next(1, durationMilliseconds - 1)),
                };
                ffmpeg
                    .GetThumbnailAsync(inputFile, outputFile, conversionOptions, token)
                    .GetAwaiter()
                    .GetResult();
                System.Drawing.Image image = System.Drawing.Image.FromFile(picPath);
            }
        }
        static System.Drawing.Image ScaleImage(
             System.Drawing.Image originalImage,
             int targetWidth,
             int targetHeight
         )
        {
            // 创建目标大小的Bitmap
            int newWidth = targetWidth;
            int newHeight = targetHeight;

            // 创建新的Bitmap
            using (Bitmap resizedBitmap = new Bitmap(newWidth, newHeight))
            {
                // 设置高质量插值模式，避免图像失真
                using (Graphics graphics = Graphics.FromImage(resizedBitmap))
                {
                    graphics.CompositingQuality = CompositingQuality.HighQuality;
                    graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
                    graphics.SmoothingMode = SmoothingMode.HighQuality;

                    // 执行缩放绘制
                    graphics.DrawImage(originalImage, 0, 0, newWidth, newHeight);
                }

                // 返回缩放后的图像
                return resizedBitmap.Clone() as System.Drawing.Image;
            }
        }
        private void PrevVideo_Click(object Sender, RoutedEventArgs Args)
        {
            if (this.picBox.Image == null)
            {
                return;
            }
            Process ffplay = new Process();
            ffplay.StartInfo.FileName = "ffplay";
            ffplay.StartInfo.WorkingDirectory = "./";
            ffplay.StartInfo.WindowStyle = ProcessWindowStyle.Normal;

            string param = "-i \"" + this.videoPath + "\" -window_title \"预览处理效果视频\" -vf \"delogo=x=" + maskX + ":y=" + maskY + ":w=" + maskWidth + ":h=" + maskHeight + ":show=0\" -x " + this.picBox.Width + " -y " + this.picBox.Height; ;

            if (maskX == 0 && maskY == 0 && maskWidth == 0 && maskHeight == 0)
            {
                param = "-i \"" + this.videoPath + "\" -window_title \"预览处理效果视频\"  -vf \"drawtext=text='时间%{pts\\:hms}':fontfile=C\\\\:/Windows/fonts/msyh.ttc:fontcolor=red:fontsize=28:x=20:y=20\" -x " + this.picBox.Width + " -y " + this.picBox.Height;
            }
            ffplay.StartInfo.Arguments = param;
            ffplay.StartInfo.CreateNoWindow = true;
            ffplay.StartInfo.RedirectStandardOutput = true;
            ffplay.StartInfo.UseShellExecute = false;
            ffplay.EnableRaisingEvents = true;

            ffplay.OutputDataReceived += (o, e) => Debug.WriteLine(e.Data ?? "NULL", "ffplay");
            ffplay.ErrorDataReceived += (o, e) => Debug.WriteLine(e.Data ?? "NULL", "ffplay");
            ffplay.Exited += (o, e) => Debug.WriteLine("Exited", "ffplay");
            ffplay.Start();
            Thread.Sleep(500);
        }
        private void PrevPic_Click(object Sender, RoutedEventArgs Args)
        {
            if (this.picBox.Image == null)
            {
                return;
            }
            Process preProcess = new Process();
            preProcess.StartInfo.FileName = "ffmpeg";
            preProcess.StartInfo.WorkingDirectory = "./";
            preProcess.StartInfo.CreateNoWindow = false;//显示命令行窗口
            preProcess.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
            TimeSpan ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
            string prevfile = picPath.Replace(".jpg", "__out__" + Convert.ToInt64(ts.TotalMilliseconds).ToString() + ".jpg");
            string param = "-i \"" + this.picPath + "\" -filter_complex  \"delogo=x=" + maskX + ":y=" + maskY + ":w=" +maskWidth + ":h=" + maskHeight + ":show=0\" \"" + prevfile + "\" -y";
            preProcess.StartInfo.Arguments = param;
            preProcess.StartInfo.CreateNoWindow = true;
            //不使用操作系统使用的shell启动进程
            preProcess.StartInfo.UseShellExecute = false;
            //将输出信息重定向
            preProcess.StartInfo.RedirectStandardInput = true;
            preProcess.StartInfo.RedirectStandardOutput = true;
            preProcess.StartInfo.RedirectStandardError = true;
            preProcess.EnableRaisingEvents = true;

            preProcess.Exited += new EventHandler((sender, e) => {
                
                picBox.Image = ScaleImage(Bitmap.FromFile(prevfile), this.picBox.Width, this.picBox.Height);
                picBox.Show();
            });
            preProcess.Start();

            //开始异步读取输出
            preProcess.BeginOutputReadLine();
            preProcess.BeginErrorReadLine();
            preProcess.WaitForExit();
        }
        async void ResetPicbox_Click(object Sender, RoutedEventArgs Args)
        {
            GetVideoInfo();
            var image = Bitmap.FromFile(picPath);
            int maxWidth = 1280;
            int w = image.Width;
            int h = image.Height;
            scale = (float)maxWidth / (float)w;
            w = maxWidth;
            h = (int)(h * scale);
            var scaleImage = ScaleImage(image, w, h);
            picBox.Image = scaleImage;
            picBox.Height = h;
            picBox.Width = w;
            this.Width = w;
            this.Height = h + 30;
            picBox.Focus();
        }
        //需要做水印处理的x
        private int maskX = 0;

        //需要做水印处理的y
        private int maskY = 0;

        //需要做水印处理的width
        private int maskWidth = 0;

        //需要做水印处理的height
        private int maskHeight = 0;
        System.Drawing.Point startPoint; //起始点
        System.Drawing.Point endPoint; //结束点
        bool blnDraw;
        bool read = true;

        private void picBox_Paint(object sender, System.Windows.Forms.PaintEventArgs e)
        {
            if (read == false)
                return;
            PictureBox pic = sender as PictureBox;
            System.Drawing.Pen pen = new System.Drawing.Pen(System.Drawing.Color.Red, 3);
            pen.DashStyle = System.Drawing.Drawing2D.DashStyle.DashDot; //绘制线的格式
            if (blnDraw)
            {
                maskX = Math.Min(startPoint.X, endPoint.X);
                maskY = Math.Min(startPoint.Y, endPoint.Y);
                maskWidth = Math.Abs(startPoint.X - endPoint.X);
                maskHeight = Math.Abs(startPoint.Y - endPoint.Y);
                e.Graphics.DrawRectangle(pen, maskX, maskY, maskWidth, maskHeight);
                blnDraw = true;
                maskX = (int)(maskX / this.scale);
                maskY = (int)(maskY / this.scale);
                maskWidth = (int)(maskWidth / this.scale);
                maskHeight = (int)(maskHeight / this.scale);
                Console.WriteLine(
                    "画完了"
                        + "\tmaskX:"
                        + maskX
                        + "\tmaskY:"
                        + maskY
                        + "\tmaskWidth:"
                        + maskWidth
                        + "\tmaskHeight:"
                        + maskHeight
                );
            }
            pen.Dispose();
        }

        private void picBox_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                startPoint = e.Location;
                blnDraw = true;
            }
        }

        private void picBox_MouseUp(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                endPoint = e.Location;
                blnDraw = false;
            }
        }

        private void picBox_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
        {
            if (blnDraw)
            {
                if (e.Button != MouseButtons.Left)
                    return;
                endPoint = e.Location;
                picBox.Invalidate(); //此代码不可省略
            }
        }

        private void PrevPic_Leave(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (!string.IsNullOrEmpty(this.picPath))
            {
                this.picBox.Image = ScaleImage(Bitmap.FromFile(this.picPath), this.picBox.Width, this.picBox.Height);
                this.picBox.Show();
            }
        }
        private Process process;

        private void Cancel_Click(object sender, RoutedEventArgs e)
        {
            if (this.picBox.Image == null)
            {
                return;
            }
            if (processing)
            {
                process.Kill();
                processing = false;

                RemoveWatermarkCommands.Instance.SpendTimeVisibility = Visibility.Hidden;
                RemoveWatermarkCommands.Instance.ProgressVisibility = Visibility.Hidden;
                RemoveWatermarkCommands.Instance.OpenVideoButtonEnabled = true;
                RemoveWatermarkCommands.Instance.DoitButtonEnabled = true;
                RemoveWatermarkCommands.Instance.StopButtonEnabled = false;
                RemoveWatermarkCommands.Instance.ResetPicBoxButtonEnabled = true;
                RemoveWatermarkCommands.Instance.PrevImageButtonEnabled = true;
                RemoveWatermarkCommands.Instance.PrevVideoButtonEnabled = true;
                RemoveWatermarkCommands.Instance.CompatibleModeEnabled = true;
                RemoveWatermarkCommands.Instance.DeviceTypeEnabled = true;
            }
        }
        private void Doit_Click(object sender, RoutedEventArgs e)
        {
            if (this.picBox.Image == null)
            {
                return;
            }

            
            RemoveWatermarkCommands.Instance.SpendTimeVisibility = Visibility.Visible;
            RemoveWatermarkCommands.Instance.ProgressVisibility = Visibility.Visible;
            RemoveWatermarkCommands.Instance.OpenVideoButtonEnabled = false;
            RemoveWatermarkCommands.Instance.DoitButtonEnabled = false;
            RemoveWatermarkCommands.Instance.StopButtonEnabled = true;
            RemoveWatermarkCommands.Instance.ResetPicBoxButtonEnabled = false;
            RemoveWatermarkCommands.Instance.PrevImageButtonEnabled = false;
            RemoveWatermarkCommands.Instance.PrevVideoButtonEnabled = false;
            RemoveWatermarkCommands.Instance.CompatibleModeEnabled = false;
            RemoveWatermarkCommands.Instance.DeviceTypeEnabled = false;

            StartTime = DateTime.Now;
            string path = Path.GetDirectoryName(this.videoPath);
            FileInfo f = new FileInfo(this.videoPath);

            string tempName = f.Name.Remove(f.Name.LastIndexOf("."));

            process = new Process();
            process.StartInfo.FileName = "ffmpeg";
            process.StartInfo.WorkingDirectory = path;
            process.StartInfo.WindowStyle = ProcessWindowStyle.Normal;

            string param = "-i \"" + this.videoPath + "\" -vf  \"delogo=x=" + maskX + ":y=" + maskY + ":w=" + maskWidth + ":h=" + maskHeight + ":show=0\" -ac 2 \"" + path + "\\" + tempName + AppConstants.WaterMark + ".mp4\" -y";
            bool IsCompatible = this.CompatibleMode.IsChecked?? false;
            if (IsCompatible)
            {
                param = "-i \"" + this.videoPath + "\" -vf  \"delogo=x=" + maskX + ":y=" + maskY + ":w=" + maskWidth + ":h=" + maskHeight + ":show=0\" -c:v h264_nvenc -gpu 0  -ac 2 \"" + path + "\\" + tempName + AppConstants.WaterMark + ".mp4\" -y";
                if (IsCompatible)
                {
                    param = "-i \"" + this.videoPath + "\" -vf  \"delogo=x=" + maskX + ":y=" + maskY + ":w=" + maskWidth + ":h=" + maskHeight + ":show=0\" -c:v h264_nvenc -gpu 0 -pix_fmt yuv420p  -ac 2 \"" + path + "\\" + tempName + AppConstants.WaterMark + ".mp4\" -y";
                }
            }
            process.StartInfo.Arguments = param;
            process.StartInfo.CreateNoWindow = true;//显示命令行窗口
            //不使用操作系统使用的shell启动进程
            process.StartInfo.UseShellExecute = false;
            //将输出信息重定向
            process.StartInfo.RedirectStandardInput = true;
            process.StartInfo.RedirectStandardOutput = true;
            process.StartInfo.RedirectStandardError = true;
            process.EnableRaisingEvents = true;

            process.Exited += new EventHandler(p_Exited);
            process.OutputDataReceived += new DataReceivedEventHandler(p_OutputDataReceived);
            process.ErrorDataReceived += new DataReceivedEventHandler(p_ErrorDataReceived);

            process.Start();
            //开始异步读取输出
            process.BeginOutputReadLine();
            process.BeginErrorReadLine();
            processing = true;
        }

        void p_OutputDataReceived(Object sender, DataReceivedEventArgs e)
        {
        }


        void p_ErrorDataReceived(Object sender, DataReceivedEventArgs e)
        {
            //这里得到的是错误信息
            string info = e.Data;
            if (info != null && info.Contains("frame") && info.Contains("fps") && info.Contains("size") && info.Contains("time") && info.Contains("bitrate") && info.Contains("speed"))
            {
                string r = "^frame.+time=(.+)bitrate=.+";
                Match match = Regex.Match(info, r);
                if (match.Success)
                {
                    string time = match.Groups[1].Value;
                    if (time.Contains("."))
                    {
                        time = time.Split(".")[0];
                    }
                    string[] times = time.Split(":");
                    int cur = int.Parse(times[0]) * 60 * 60 + int.Parse(times[1]) * 60 + int.Parse(times[2]);
                    double rx = Math.Round((Convert.ToDouble(cur) / Duration), 2) * 100;
                    RemoveWatermarkCommands.Instance.Progress = $"进度 {rx.ToString("0.00")}%";
                    string st = new TimeSpan(DateTime.Now.Ticks - StartTime.Ticks).ToString(@"hh\:mm\:ss");
                    RemoveWatermarkCommands.Instance.SpendTime = $"耗时 {st}";
                    TimeSpan span = new TimeSpan(DateTime.Now.Ticks - StartTime.Ticks);    //获取当前时间的刻度数
                    if(RemoveWatermarkCommands.Instance.Progress.Contains("100"))
                    {
                        RemoveWatermarkCommands.Instance.SpendTimeVisibility = Visibility.Hidden;
                        RemoveWatermarkCommands.Instance.ProgressVisibility = Visibility.Hidden;
                        RemoveWatermarkCommands.Instance.OpenVideoButtonEnabled = true;
                        RemoveWatermarkCommands.Instance.DoitButtonEnabled = true;
                        RemoveWatermarkCommands.Instance.StopButtonEnabled = false;
                        RemoveWatermarkCommands.Instance.ResetPicBoxButtonEnabled = true;
                        RemoveWatermarkCommands.Instance.PrevImageButtonEnabled = true;
                        RemoveWatermarkCommands.Instance.PrevVideoButtonEnabled = true;
                        RemoveWatermarkCommands.Instance.CompatibleModeEnabled = true;
                        RemoveWatermarkCommands.Instance.DeviceTypeEnabled = true;
                    }
                }
            }
        }

        void p_Exited(Object sender, EventArgs e)
        {
            RemoveWatermarkCommands.Instance.SpendTimeVisibility = Visibility.Hidden;
            RemoveWatermarkCommands.Instance.ProgressVisibility = Visibility.Hidden;
            RemoveWatermarkCommands.Instance.OpenVideoButtonEnabled = true;
            RemoveWatermarkCommands.Instance.DoitButtonEnabled = true;
            RemoveWatermarkCommands.Instance.StopButtonEnabled = false;
            RemoveWatermarkCommands.Instance.ResetPicBoxButtonEnabled = true;
            RemoveWatermarkCommands.Instance.PrevImageButtonEnabled = true;
            RemoveWatermarkCommands.Instance.PrevVideoButtonEnabled = true;
            RemoveWatermarkCommands.Instance.CompatibleModeEnabled = true;
            RemoveWatermarkCommands.Instance.DeviceTypeEnabled = true;
        }
    }
}
